﻿using System.Collections.Generic;
using System.Reflection;
using smp.QueryDb.Structure;

namespace smp.QueryDb
{
    public interface INestedMapTo<TViewModel>
    {
        NestedMap<TViewModel> To(Column column);

        NestedMap<TViewModel> ToNested<TNestedModel>(NestedMap<TNestedModel> nestedMap);
    }

    internal class NestedMapTo<TViewModel> : INestedMapTo<TViewModel>
    {
        private readonly NestedMap<TViewModel> _nested;
        private readonly PropertyInfo _property;

        internal NestedMapTo(NestedMap<TViewModel> nested, PropertyInfo property)
        {
            _nested = nested;
            _property = property;
        }

        public NestedMap<TViewModel> To(Column column)
        {
            _nested.AddMap(_property, column);
            return _nested;
        }

        public NestedMap<TViewModel> ToNested<TNestedModel>(NestedMap<TNestedModel> nestedMap)
        {
            if(Helper.IsCollection(_property))
            {
                throw Helper.Error("Property {0} on entity {1} is invalid for mapping, nested collections are not supported as bad practice.",
                    _property.Name,
                    typeof (TViewModel).Name);
            }
            _nested.AddNestedMap(_property, nestedMap.Maps);
            return _nested;
        }
    }

    public interface INestedMapAllTo<TViewModel>
    {
        NestedMap<TViewModel> To(Table table);
    }

    internal class NestedMapAllTo<TViewModel> : INestedMapAllTo<TViewModel>
    {
        private readonly NestedMap<TViewModel> _nested;
        private readonly List<PropertyInfo> _properties;

        internal NestedMapAllTo(NestedMap<TViewModel> nested)
        {
            _nested = nested;
            _properties = new List<PropertyInfo>();
            foreach (var property in typeof(TViewModel).GetProperties())
            {
                if (!property.PropertyType.IsValueType || property.PropertyType != typeof(string))
                    continue;
                _properties.Add(property);
            }
        }

        #region Implementation of IQueryMapAllTo<TViewModel>

        public NestedMap<TViewModel> To(Table table)
        {
            var idProperty = _properties.Find(x => x.Name == table.Id.Name);
            if (idProperty != null)
            {
                _nested.AddMap(idProperty, table.Id);
            }
            foreach (var column in table.Columns)
            {
                var columnProperty = _properties.Find(x => x.Name == column.Name);
                if (columnProperty != null)
                {
                    _nested.AddMap(columnProperty, column);
                }
            }
            return _nested;
        }

        #endregion
    }
}
